package com.lifeverse.repository;

import com.lifeverse.entity.PerformanceMetric;
import com.lifeverse.entity.enums.MetricStatus;
import com.lifeverse.entity.enums.MetricType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 性能指标数据访问层
 */
@Repository
public interface PerformanceMetricRepository extends JpaRepository<PerformanceMetric, Long> {
    
    /**
     * 根据指标名称查找最新的指标
     */
    Optional<PerformanceMetric> findTopByMetricNameOrderByMeasuredAtDesc(String metricName);
    
    /**
     * 根据指标名称和组件名称查找最新的指标
     */
    Optional<PerformanceMetric> findTopByMetricNameAndComponentNameOrderByMeasuredAtDesc(
            String metricName, String componentName);
    
    /**
     * 根据指标类型查找指标
     */
    Page<PerformanceMetric> findByMetricType(MetricType metricType, Pageable pageable);
    
    /**
     * 根据指标状态查找指标
     */
    Page<PerformanceMetric> findByStatus(MetricStatus status, Pageable pageable);
    
    /**
     * 根据组件名称查找指标
     */
    Page<PerformanceMetric> findByComponentName(String componentName, Pageable pageable);
    
    /**
     * 根据时间范围查找指标
     */
    Page<PerformanceMetric> findByMeasuredAtBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);
    
    /**
     * 查找异常指标
     */
    Page<PerformanceMetric> findByIsAnomalyTrue(Pageable pageable);
    
    /**
     * 根据指标名称和时间范围查找指标
     */
    List<PerformanceMetric> findByMetricNameAndMeasuredAtBetweenOrderByMeasuredAtAsc(
            String metricName, LocalDateTime startTime, LocalDateTime endTime);
    
    /**
     * 根据指标名称、组件名称和时间范围查找指标
     */
    List<PerformanceMetric> findByMetricNameAndComponentNameAndMeasuredAtBetweenOrderByMeasuredAtAsc(
            String metricName, String componentName, LocalDateTime startTime, LocalDateTime endTime);
    
    /**
     * 查找需要关注的指标（警告、异常、临界状态）
     */
    @Query("SELECT pm FROM PerformanceMetric pm WHERE pm.status IN ('WARNING', 'ABNORMAL', 'CRITICAL') " +
           "ORDER BY pm.measuredAt DESC")
    Page<PerformanceMetric> findMetricsNeedingAttention(Pageable pageable);
    
    /**
     * 查找指定时间范围内的异常指标
     */
    @Query("SELECT pm FROM PerformanceMetric pm WHERE pm.isAnomaly = true " +
           "AND pm.measuredAt BETWEEN :startTime AND :endTime ORDER BY pm.anomalyScore DESC")
    List<PerformanceMetric> findAnomaliesInTimeRange(@Param("startTime") LocalDateTime startTime,
                                                    @Param("endTime") LocalDateTime endTime);
    
    /**
     * 统计指定时间范围内各状态的指标数量
     */
    @Query("SELECT pm.status, COUNT(pm) FROM PerformanceMetric pm " +
           "WHERE pm.measuredAt BETWEEN :startTime AND :endTime " +
           "GROUP BY pm.status")
    List<Object[]> countMetricsByStatus(@Param("startTime") LocalDateTime startTime,
                                      @Param("endTime") LocalDateTime endTime);
    
    /**
     * 统计指定时间范围内各类型的指标数量
     */
    @Query("SELECT pm.metricType, COUNT(pm) FROM PerformanceMetric pm " +
           "WHERE pm.measuredAt BETWEEN :startTime AND :endTime " +
           "GROUP BY pm.metricType")
    List<Object[]> countMetricsByType(@Param("startTime") LocalDateTime startTime,
                                    @Param("endTime") LocalDateTime endTime);
    
    /**
     * 获取指定指标的平均值
     */
    @Query("SELECT AVG(pm.metricValue) FROM PerformanceMetric pm " +
           "WHERE pm.metricName = :metricName AND pm.measuredAt BETWEEN :startTime AND :endTime")
    Optional<BigDecimal> getAverageMetricValue(@Param("metricName") String metricName,
                                             @Param("startTime") LocalDateTime startTime,
                                             @Param("endTime") LocalDateTime endTime);
    
    /**
     * 获取指定指标的最大值
     */
    @Query("SELECT MAX(pm.metricValue) FROM PerformanceMetric pm " +
           "WHERE pm.metricName = :metricName AND pm.measuredAt BETWEEN :startTime AND :endTime")
    Optional<BigDecimal> getMaxMetricValue(@Param("metricName") String metricName,
                                         @Param("startTime") LocalDateTime startTime,
                                         @Param("endTime") LocalDateTime endTime);
    
    /**
     * 获取指定指标的最小值
     */
    @Query("SELECT MIN(pm.metricValue) FROM PerformanceMetric pm " +
           "WHERE pm.metricName = :metricName AND pm.measuredAt BETWEEN :startTime AND :endTime")
    Optional<BigDecimal> getMinMetricValue(@Param("metricName") String metricName,
                                         @Param("startTime") LocalDateTime startTime,
                                         @Param("endTime") LocalDateTime endTime);
    
    /**
     * 获取指定组件的所有指标类型
     */
    @Query("SELECT DISTINCT pm.metricType FROM PerformanceMetric pm WHERE pm.componentName = :componentName")
    List<MetricType> getMetricTypesByComponent(@Param("componentName") String componentName);
    
    /**
     * 获取所有组件名称
     */
    @Query("SELECT DISTINCT pm.componentName FROM PerformanceMetric pm WHERE pm.componentName IS NOT NULL")
    List<String> getAllComponentNames();
    
    /**
     * 获取所有指标名称
     */
    @Query("SELECT DISTINCT pm.metricName FROM PerformanceMetric pm")
    List<String> getAllMetricNames();
    
    /**
     * 查找超出阈值的指标
     */
    @Query("SELECT pm FROM PerformanceMetric pm WHERE " +
           "(pm.thresholdMin IS NOT NULL AND pm.metricValue < pm.thresholdMin) OR " +
           "(pm.thresholdMax IS NOT NULL AND pm.metricValue > pm.thresholdMax) " +
           "ORDER BY pm.measuredAt DESC")
    Page<PerformanceMetric> findMetricsOutOfThreshold(Pageable pageable);
    
    /**
     * 查找指定时间范围内超出阈值的指标
     */
    @Query("SELECT pm FROM PerformanceMetric pm WHERE " +
           "pm.measuredAt BETWEEN :startTime AND :endTime AND " +
           "((pm.thresholdMin IS NOT NULL AND pm.metricValue < pm.thresholdMin) OR " +
           "(pm.thresholdMax IS NOT NULL AND pm.metricValue > pm.thresholdMax)) " +
           "ORDER BY pm.measuredAt DESC")
    List<PerformanceMetric> findMetricsOutOfThresholdInTimeRange(@Param("startTime") LocalDateTime startTime,
                                                               @Param("endTime") LocalDateTime endTime);
    
    /**
     * 获取指标趋势数据
     */
    @Query("SELECT pm.measuredAt, pm.metricValue FROM PerformanceMetric pm " +
           "WHERE pm.metricName = :metricName AND pm.componentName = :componentName " +
           "AND pm.measuredAt BETWEEN :startTime AND :endTime " +
           "ORDER BY pm.measuredAt ASC")
    List<Object[]> getMetricTrendData(@Param("metricName") String metricName,
                                    @Param("componentName") String componentName,
                                    @Param("startTime") LocalDateTime startTime,
                                    @Param("endTime") LocalDateTime endTime);
    
    /**
     * 删除指定时间之前的指标数据（用于数据清理）
     */
    @Query("DELETE FROM PerformanceMetric pm WHERE pm.measuredAt < :cutoffTime")
    void deleteOldMetrics(@Param("cutoffTime") LocalDateTime cutoffTime);
    
    /**
     * 获取系统健康状况概览
     */
    @Query("SELECT " +
           "COUNT(CASE WHEN pm.status = 'NORMAL' THEN 1 END) as normalCount, " +
           "COUNT(CASE WHEN pm.status = 'WARNING' THEN 1 END) as warningCount, " +
           "COUNT(CASE WHEN pm.status = 'ABNORMAL' THEN 1 END) as abnormalCount, " +
           "COUNT(CASE WHEN pm.status = 'CRITICAL' THEN 1 END) as criticalCount " +
           "FROM PerformanceMetric pm WHERE pm.measuredAt > :since")
    Object[] getSystemHealthOverview(@Param("since") LocalDateTime since);
    
    /**
     * 获取性能趋势摘要
     */
    @Query("SELECT pm.metricName, pm.componentName, " +
           "AVG(pm.metricValue) as avgValue, " +
           "MAX(pm.metricValue) as maxValue, " +
           "MIN(pm.metricValue) as minValue, " +
           "COUNT(pm) as sampleCount " +
           "FROM PerformanceMetric pm " +
           "WHERE pm.measuredAt BETWEEN :startTime AND :endTime " +
           "GROUP BY pm.metricName, pm.componentName " +
           "ORDER BY pm.metricName, pm.componentName")
    List<Object[]> getPerformanceTrendSummary(@Param("startTime") LocalDateTime startTime,
                                            @Param("endTime") LocalDateTime endTime);
}